/*
 *  Copyright 2009 Advanced Industrial Science and Technology (AIST).
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/*! \file
 *  \brief
 */
#pragma once

#include <thrust/graph/detail/edge_iterator_base.hpp>

namespace thrust {

namespace detail {
  struct edge_iter_friend;
} // end namespace detail

template <typename Iter, 
          typename EdgeDescriptor,
          typename CalledSpace>
class edge_iter 
  : public detail::edge_iter_base<Iter,EdgeDescriptor,CalledSpace>::type
{
private:
  typedef edge_iter<Iter,EdgeDescriptor,CalledSpace> self_t;
  typedef typename detail::edge_iter_base<Iter,EdgeDescriptor,CalledSpace>::type super_t;
  friend class thrust::experimental::iterator_core_access;
  friend struct detail::edge_iter_friend;

public:
  typedef CalledSpace called_space;
  
public:
  __host__ __device__
  edge_iter() {}
  
  __host__ __device__
  edge_iter( const Iter& iter) : super_t(iter) {}

public:
  __host__ __device__
  inline EdgeDescriptor
  operator*() const
  {
    return operator*( CalledSpace());
  }
  
private:

  //
  // Notice:
  // this->base() is device_vector<edge_descriptor>::iterator
  //
  __host__ __device__
  inline EdgeDescriptor
  operator*( thrust::called_from_host_tag) const
  {
    const Iter &iter =this->base();
    return *iter;
  }
  
  //
  // Notice:
  // this->base() is device_vector<edge_descriptor>::iterator 
  // this->base().base() is device_ptr<edge_descriptor>
  // this->base().base().get() is *edge_descriptor
  //
  __device__
  inline EdgeDescriptor
  operator*( thrust::called_from_device_tag) const
  {
    const Iter &iter =this->base();
    return *(iter.base().get());
  }

  __device__
  inline EdgeDescriptor&
  dereference() const
  {
    const Iter &iter =this->base();
    return *(iter.base().get());
  }
};

} // end namespace thrust
#include <thrust/graph/detail/edge_iterator.inl>
